﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using ProcessRoll.Models;
using ProcessRoll.Utilities;

namespace ProcessRoll.BLL
{
    public enum EA_State
    {
       Success,Failed_Input_Error
    }
    public class FlowEA
    {
        Process _process;
        public Process Process
        {
            get { return _process; }
        }
        ActivityInstance _currentActivityInstance;
        public ActivityInstance CurrentActivityInstance
        {
            get { return _currentActivityInstance; }
        }
        ProcessInstance _processInstance;
        public ProcessInstance ProcessInstance
        {
            get { return _processInstance; }
        }


        public FlowEA(ProcessInstance pi)
        {
            _processInstance = pi;
            _currentActivityInstance = pi.ActivityInstances != null ? pi.ActivityInstances.Last() : null;
            var v = Validate(pi.Process, _currentActivityInstance);
            if (v == EA_State.Success)
            {
               
            }
            else
            {
                throw new Exception(v.ToString());
            }
        }

        public ProcessInstance GetNextParticipant()
        {
            var a = new ActivityInstance();
            var next = GetNextActivity(_currentActivityInstance ==null? null:_currentActivityInstance.Activity);
            if (next != null)
            {
                a.ActivityID = next.ID;
                a.Activity = next;
                if (_processInstance.ActivityInstances == null) _processInstance.ActivityInstances = new List<ActivityInstance>();
                _processInstance.ActivityInstances.Add(a);
            }
            return _processInstance;
        }

        Activity GetNextActivity(Activity ca)
        {
            Activity next = null;

            //取得第一环节，当前环节为Null
            if (ca == null)
            {
                var nq = CH.GetAllData<Queue>(q => q.Sequence == 1, "Containers").FirstOrDefault();
                next = ParseContainers(nq.Containers);
            }
            else
            {
                //取得当前环节的下一环节
                ca = CH.GetDataById<Activity>(ca.ID);//重新读取，为了取得sequence
                next = CH.GetAllData<Activity>(a => a.Sequence == ca.Sequence + 1 && a.ContainerID == ca.ContainerID).FirstOrDefault();
                if (next == null)
                {
                    var nq = CH.GetAllData<Queue>(q => q.Sequence == ca.Container.Queue.Sequence + 1).FirstOrDefault();
                    if (nq == null)
                        return null;//审批完成
                        //throw new Exception("未找到对应下一个环节，也未找到对应下一个队列，请验证数据是否完整");

                    next = ParseContainers(CH.GetAllData<Container>(c => c.QueueID == nq.ID));
                }
            }
            return next;
        }

        private Activity ParseContainers(List<Container> list)
        {
            var orderedContainers = list.OrderBy(i=>i.Sequence);
            Container targetContainer = null;

            foreach(var c in  orderedContainers)
            {
                if (IsSatisfied(c))
                {
                    targetContainer = c;
                    break;
                }
            }
            if(targetContainer!=null)
            {
                var activity = CH.GetAllData<Activity>(a => a.Sequence == 1 && a.ContainerID == targetContainer.ID).FirstOrDefault();
                return activity;
            }

            return null;
        }

        private bool IsSatisfied(Container c)
        {
            return ParseNode(CH.GetAllData<NodeData>(n=>n.ContainerID == c.ID && n.ParentNodeDataID ==null).FirstOrDefault());
        }

        public bool ParseNode(NodeData nd)
        {
            if (nd.Condition != null)
            {
                var c = nd.Condition;
                var cf = nd.Condition.Field;
                var value = nd.Condition.ConditionValue;
                if (cf == null) throw new Exception("条件的表单为null,数据不完整");
                var fis =  _currentActivityInstance == null? _processInstance.ApplyMsg.FieldInstances : _currentActivityInstance.ExameApprove.FieldInstances;
                var fi =fis.Find(f => f.FieldName == cf.FieldName);
                if (c.ConditionType == "currency" || c.ConditionType == "number")
                    return Operator.Run(c.ConditionOperator, Convert.ToDouble(fi.FieldValue), Convert.ToDouble(value));
                else if (c.ConditionType == "time")
                    return Operator.Run(c.ConditionOperator, Convert.ToDateTime(fi.FieldValue), Convert.ToDateTime(value));
                else
                    return Operator.Run(c.ConditionOperator, fi.FieldValue, value);
            }
            else
            {
                if (nd.Operator == "&&")
                {
                    foreach (var child in nd.ChildrenData)
                    {
                        var result = ParseNode(child);
                        if (!result)
                            return false;
                    }
                }
                if (nd.Operator == "||")
                {
                    foreach (var child in nd.ChildrenData)
                    {
                        var result = ParseNode(child);
                        if (result)
                            return true;
                    }
                }
            }
            return true;
        }

        public EA_State Validate(Process p, ActivityInstance f)
        {
            return EA_State.Success;
        }
    }

    public class Operator
    {
        static Func<int, int, bool> equalsInt = (x, y) => x == y;
        static Func<int, int, bool> greate_equalsInt = (x, y) => x >= y;
        static Func<int, int, bool> less_equalsInt = (x, y) => x <= y;
        static Func<int, int, bool> greateInt = (x, y) => x >= y;
        static Func<int, int, bool> lessInt = (x, y) => x <= y;

        static Func<DateTime, DateTime, bool> equalsDate = (x, y) => x == y;
        static Func<DateTime, DateTime, bool> greate_equalsDate = (x, y) => x >= y;
        static Func<DateTime, DateTime, bool> less_equalsDate = (x, y) => x <= y;
        static Func<DateTime, DateTime, bool> greateDate = (x, y) => x >= y;
        static Func<DateTime, DateTime, bool> lessDate = (x, y) => x <= y;

        static Func<double, double, bool> equalsDouble = (x, y) => x == y;
        static Func<double, double, bool> greate_equalsDouble = (x, y) => x >= y;
        static Func<double, double, bool> less_equalsDouble = (x, y) => x <= y;
        static Func<double, double, bool> greateDouble = (x, y) => x >= y;
        static Func<double, double, bool> lessDouble = (x, y) => x <= y;


        static Func<string, string, bool> equalsString = (x, y) => x == y;
        static Func<string, string, bool> inString = (x, y) => y.Contains(x);

        public static bool Run(string symbol, int par1, int par2)
        {
            if (symbol=="=")
                return equalsInt(par1, par2);
            if (symbol == ">=")
                return greate_equalsInt(par1, par2);
            if (symbol == "<=")
                return less_equalsInt(par1, par2);
            if (symbol == ">")
                return greateInt(par1, par2);
            if (symbol == "<")
                return lessInt(par1, par2);
            return false;
        }

        public static bool Run(string symbol, DateTime par1, DateTime par2)
        {
            if (symbol == "=")
                return equalsDate(par1, par2);
            if (symbol == ">=")
                return greate_equalsDate(par1, par2);
            if (symbol == "<=")
                return less_equalsDate(par1, par2);
            if (symbol == ">")
                return greateDate(par1, par2);
            if (symbol == "<")
                return lessDate(par1, par2);
            return false;
        }


        public static bool Run(string symbol, double par1, double par2)
        {
            if (symbol == "=")
                return equalsDouble(par1, par2);
            if (symbol == ">=")
                return greate_equalsDouble(par1, par2);
            if (symbol == "<=")
                return less_equalsDouble(par1, par2);
            if (symbol == ">")
                return greateDouble(par1, par2);
            if (symbol == "<")
                return lessDouble(par1, par2);
            return false;
        }

        public static bool Run(string symbol, string par1, string par2)
        {
            if (symbol == "=")
                return equalsString(par1, par2);
            if (symbol == "in")
                return inString(par1, par2);
            if (symbol == "not in")
                return !inString(par1, par2);

            return false;
        }
    }
}